/*
 * Copyright (C) 2009-2010 Trinity <http://www.trinitycore.org/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/* ScriptData
SDName: toravon
SDAuthor: jwladi (Nieve)
SD%Complete: 90%
TODO: Verify frost warder and adjust timing and maybe damages
EndScriptData */

/*** SQL START ***
UPDATE `creature_template` SET `ScriptName`='boss_toravon' WHERE `entry`='38433';
UPDATE `creature_template` SET `ScriptName`='mob_frost_warder' WHERE `entry`='38482';
UPDATE `creature_template` SET `ScriptName`='mob_frozen_orb' WHERE `entry`='38456';
*** SQL END ***/


#include "ScriptedPch.h"
#include "vault_of_archavon.h"

// Spells Toravon
#define SPELL_FREEZING_GROUND				RAID_MODE(72090,72104)  // don't know cd... using 20 secs.
#define SPELL_WHITEOUT						RAID_MODE(72034,72096)	// Casted after FROZEN ORB dies
#define SPELL_WHITEOUT_VISUAL				72036					// Casted after SPELL_WHITEOUT
#define SPELL_FROZEN_MALLET					RAID_MODE(72122,71993)  // Casted on tank every 5 secs

// Spells Frost Warder
#define SPELL_FROST_BLAST					RAID_MODE(72123,72124)      // don't know cd... using 20 secs.
#define SPELL_FROZEN_MALLET_WARDER			72122

// Spell Frozen Orb
#define SPELL_FROZEN_ORB_DMG				72081   // priodic dmg aura
#define SPELL_FROZEN_ORB_AURA				72067   // make visible

// Spell Frozen Orb Stalker
#define SPELL_FROZEN_ORB_SUMMON				72094   // summon orb with visual effect

// Events boss
#define EVENT_FREEZING_GROUND					1
#define EVENT_FROZEN_ORB						2
#define EVENT_FROZEN_MALLET						3

// Events mob
#define EVENT_FROST_BLAST						4

// Mob Frozen Orb
#define NPC_FROZEN_ORB_STALKER				38461  // Npc for visual spawn of frozen orb
#define NPC_TORAVON_STALKER					38439  // Npc for visual Whiteout

bool orb_spawned;

void SummonOrb(Creature* c, uint32 num_orbs) {

	if (!c) return;
	
	for (uint8 i=0; i<num_orbs; ++i) {
        Position pos;
		float dist, angle;

		dist = (float)urand(6, 16);
		angle = (float)(rand_chance())*2.0*3.141592/100.0;
		
		pos.m_orientation = 0.0f;
		c->GetNearPoint(c, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, dist, angle);
		if (Creature *Stalker = c->SummonCreature(NPC_FROZEN_ORB_STALKER, pos, TEMPSUMMON_TIMED_DESPAWN, 12000)) {
			Stalker->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_DISABLE_MOVE);
			Stalker->SetReactState(REACT_PASSIVE);
			Stalker->AddAura(SPELL_FROZEN_ORB_SUMMON, Stalker);
		}
		
	}
	orb_spawned = true;
}

void WhiteoutEffect(ScriptedInstance *pInstance, uint64 spell) {
	if (pInstance){
		Unit* pToravon;

		

		if (pToravon = pInstance->instance->GetCreature(pInstance->GetData64(DATA_TORAVON))) {
			Position pos;
			
			pToravon->CastSpell(pToravon, spell, true);

			pos.m_positionX = pToravon->GetPositionX();
			pos.m_positionY = pToravon->GetPositionY();
			pos.m_positionZ = pToravon->GetPositionZ();
			pos.m_orientation = 0.0;

			if (Creature *Stalker = pToravon->SummonCreature(NPC_TORAVON_STALKER, pos, TEMPSUMMON_TIMED_DESPAWN, 8000)) {
				Stalker->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_DISABLE_MOVE);
				Stalker->SetReactState(REACT_PASSIVE);
				Stalker->CastSpell(Stalker, SPELL_WHITEOUT_VISUAL, true);
			}
		}
	}
}

struct boss_toravonAI : public ScriptedAI
{
    boss_toravonAI(Creature *c) : ScriptedAI(c)
    {
        pInstance = c->GetInstanceData();
    }

    ScriptedInstance *pInstance;
    EventMap events;

    void Reset()
    {
        events.Reset();
		orb_spawned = false;


        if (pInstance)
            pInstance->SetData(DATA_TORAVON_EVENT, NOT_STARTED);
    }

    void KilledUnit(Unit* Victim) {}

    void JustDied(Unit* Killer)
    {
        if (pInstance)
            pInstance->SetData(DATA_TORAVON_EVENT, DONE);
    }

    void EnterCombat(Unit *who)
    {
        DoZoneInCombat();

        DoCast(me, SPELL_FROZEN_MALLET);

        events.ScheduleEvent(EVENT_FROZEN_ORB, 11000);
        events.ScheduleEvent(EVENT_FREEZING_GROUND, 15000);
		events.ScheduleEvent(EVENT_FROZEN_MALLET, 8000);

        if (pInstance)
            pInstance->SetData(DATA_TORAVON_EVENT, IN_PROGRESS);
    }

    void UpdateAI(const uint32 diff)
    {
        if (!UpdateVictim())
            return;

        events.Update(diff);

        if (m_creature->hasUnitState(UNIT_STAT_CASTING))
            return;

        while(uint32 eventId = events.ExecuteEvent())
        {
            switch(eventId)
            {
                case EVENT_FROZEN_ORB:
					if (!orb_spawned)
						SummonOrb(m_creature, RAID_MODE(1, 3));
		
					events.ScheduleEvent(EVENT_FROZEN_ORB, 38000);
                    return;
                case EVENT_FREEZING_GROUND:
                    if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0))
                        DoCast(pTarget, SPELL_FREEZING_GROUND);

                    events.ScheduleEvent(EVENT_FREEZING_GROUND, 20000);
                    return;
				case EVENT_FROZEN_MALLET:
                    if (Unit *pTarget = SelectUnit(SELECT_TARGET_TOPAGGRO, 0))
                        DoCast(pTarget, SPELL_FROZEN_MALLET);

                    events.ScheduleEvent(EVENT_FROZEN_MALLET, 8000);
                    return;
            }
        }
        DoMeleeAttackIfReady();
    }
};

/*######
##  Mob Frozen Orb
######*/
struct mob_frozen_orbAI : public ScriptedAI
{
    mob_frozen_orbAI(Creature *c) : ScriptedAI(c) {
		done = false;
		pInstance = c->GetInstanceData();
	}
	
	ScriptedInstance *pInstance;
    bool done;
    uint32 killtimer;

    void Reset()
    {
        
        killtimer = 60000; // if after this time there is no victim -> destroy!
    }

    void EnterCombat(Unit *who)
    {
        DoZoneInCombat();
    }

	void JustDied(Unit* Killer) {
		orb_spawned = false;
		WhiteoutEffect(pInstance, SPELL_WHITEOUT);
	}

    void UpdateAI(const uint32 diff)
    {
        if (!done)
        {
            DoCast(me, SPELL_FROZEN_ORB_AURA, true);
            DoCast(me, SPELL_FROZEN_ORB_DMG, true);
            done = true;
        }

        if (killtimer <= diff)
        {
			if (!UpdateVictim()) {
                m_creature->ForcedDespawn();
				orb_spawned = false;
			}
            killtimer = 10000;
        }
        else
            killtimer -= diff;
    }
};

/*######
##  Mob Frost Warder
######*/
struct mob_frost_warderAI : public ScriptedAI
{
    mob_frost_warderAI(Creature *c) : ScriptedAI(c) {}

    EventMap events;

    void Reset()
    {
        events.Reset();
    }

    void EnterCombat(Unit *who)
    {
        DoZoneInCombat();

        DoCast(me, SPELL_FROZEN_MALLET_WARDER);

        events.ScheduleEvent(EVENT_FROST_BLAST, 5000);
    }

    void UpdateAI(const uint32 diff)
    {
        if (!UpdateVictim())
            return;

        events.Update(diff);

        while(uint32 eventId = events.ExecuteEvent())
        {
            switch(eventId)
            {
                case EVENT_FROST_BLAST:
                    DoCast(m_creature->getVictim(), SPELL_FROST_BLAST);
                    events.ScheduleEvent(EVENT_FROST_BLAST, 20000);
                    return;
            }
        }
        DoMeleeAttackIfReady();
    }
};

CreatureAI* GetAI_boss_toravon(Creature* pCreature)
{
    return new boss_toravonAI (pCreature);
}

CreatureAI* GetAI_mob_frozen_orb(Creature* pCreature)
{
    return new mob_frozen_orbAI (pCreature);
}

CreatureAI* GetAI_mob_frost_warder(Creature* pCreature)
{
    return new mob_frost_warderAI (pCreature);
}

void AddSC_boss_toravon()
{
    Script *newscript;

    newscript = new Script;
    newscript->Name = "boss_toravon";
    newscript->GetAI = &GetAI_boss_toravon;
    newscript->RegisterSelf();

    newscript = new Script;
    newscript->Name = "mob_frozen_orb";
    newscript->GetAI = &GetAI_mob_frozen_orb;
    newscript->RegisterSelf();

	newscript = new Script;
    newscript->Name = "mob_frost_warder";
    newscript->GetAI = &GetAI_mob_frost_warder;
    newscript->RegisterSelf();


}


/*sqls
-- Faction of frozen orb
update creature_template set faction_A=16, faction_H=16 where entry = 38456;

-- Delete spawn of Frozen orb stalker if exists
delete from creature where id = 38461

-- Fix modelid of stalkers and update scriptname to ''
update creature_template set modelid1=11686, modelid2=0, scriptname='' where entry in (38461, 38439);
*/
